import type { PlatformTypeValue } from '../../../types/interfaces'
import { BaseModule } from '../../../lib/abstract'
import { PageHandler } from '../../../lib/page_handler'
import { GiteePageType } from '../../../lib/page_handler/platform/gitee/types'
import { ToolKit } from '../../../lib/utils/toolkit'
import {
  HOSTNAME,
  logger,
  REDIRECT_RULES,
  SUPPORTED_PLATFORMS,
} from '../../../types/constants'
import { REGEXP_PATTERNS } from '../../../types/constants/regexp'
import { ConfigManager } from '../../config_manager'

interface Config {
  enabled?: boolean
}

interface LinkDirectConfig {
  whiteList?: string[] // 白名单选择器
}
type LinkDirectPlatformConfig = Partial<Record<PlatformTypeValue, Record<string, LinkDirectConfig>>>

export class LinkDirect extends BaseModule {
  readonly id: string = 'link_direct'
  readonly name: string = 'LinkDirect'
  readonly isInitialized: boolean = false
  readonly supportedPlatforms: string[] = ConfigManager.getInstance().moduleSupportedPlatforms(this.name)
  private static instance: LinkDirect

  get currentConfig(): LinkDirectConfig | undefined {
    return this.getCurrentConfig()
  }

  config: Config = {
    enabled: true,
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): LinkDirect {
    if (!LinkDirect.instance) {
      LinkDirect.instance = new LinkDirect()
    }
    return LinkDirect.instance
  }

  destroy(): void {
    super.destroy()
  }

  core(): void {
    this.loadConfig()

    if (!this.config.enabled)
      return

    this.setupLink()
  }

  onToggleCallback(_id: string, checked: boolean): void {
    super.onToggleCallback(_id, checked)
  }

  /**
   * 获取当前页面的配置
   */
  getCurrentConfig(): LinkDirectConfig | undefined {
    const config: LinkDirectPlatformConfig = {
      [SUPPORTED_PLATFORMS.GITEE]: {
        [GiteePageType.Project]: {
          whiteList: [
            '#tree-content-holder .tree-content',
          ],
        },
      },
    }

    return config[HOSTNAME]?.[PageHandler.getCurrentPageType()]
  }

  /**
   * 检查元素是否是 h1-h6 标题元素
   * @param element 要检查的元素
   * @returns 是否是标题元素
   */
  private isHeadingElement(element: HTMLElement): boolean {
    return REGEXP_PATTERNS.element.articleHeading.test(element.tagName)
  }

  /**
   * 查找最近的链接元素
   * @param element 起始元素
   * @returns 找到的链接元素或null
   */
  private findClosestLink(element: HTMLElement): HTMLAnchorElement | null {
    let current: HTMLElement | null = element

    // 1. 首先尝试向上查找最近的<a>元素
    while (current && current !== document.body) {
      if (current.tagName === 'A') {
        return current as HTMLAnchorElement
      }
      current = current.parentElement
    }

    // 2. 如果向上查找失败，且当前元素是 h1-h6 标题，尝试向下查找第一个符合条件的<a>子元素
    if (element && element !== document.body && this.isHeadingElement(element)) {
      const childLinks = element.querySelectorAll('a')
      for (let i = 0; i < childLinks.length; i++) {
        const link = childLinks[i] as HTMLAnchorElement
        if (link.href && !this.isAnchorLink(link)) {
          return link
        }
      }
    }

    return null
  }

  /**
   * 检查是否是锚点链接
   * @param link 链接元素
   * @returns 是否是锚点链接
   */
  private isAnchorLink(link: HTMLAnchorElement): boolean {
    return link.getAttribute('href')?.startsWith('#') ?? false
  }

  /**
   * 检查链接是否为空
   * @param link 链接元素
   * @returns 是否为空链接
   */
  private isEmptyLink(link: HTMLAnchorElement): boolean {
    return link.getAttribute('href') === ''
      || link.getAttribute('href') === null
      || link.getAttribute('href') === undefined
  }

  /**
   * 设置链接点击事件
   */
  setupLink(): void {
    // 知乎页面不执行，因为会影响到页面中链接转卡片的功能
    if (![SUPPORTED_PLATFORMS.ZHI_HU].includes(HOSTNAME))
      ToolKit.dom.removeNativeEventListeners('a', this.currentConfig?.whiteList)

    // 移除所有链接上的 onclick 处理器（除了白名单内的）
    document.querySelectorAll('a[onclick]').forEach((link) => {
      if (this.isInWhiteList(link as HTMLElement))
        return

      link.removeAttribute('onclick')
    })

    document.addEventListener('click', (e) => {
      // 使用实际触发事件的元素（最内层元素）target，而不是绑定事件处理程序的元素 currentTarget
      const el = e.target as HTMLElement

      // 检查是否在白名单内
      if (this.isInWhiteList(el))
        return

      const link = this.findClosestLink(el)

      if (!link || this.isAnchorLink(link) || this.isEmptyLink(link))
        return

      // 阻止默认行为
      e.preventDefault()
      e.stopImmediatePropagation()

      // 处理链接重定向
      this.processLinkRedirect(link)
    })
  }

  /**
   * 检查元素是否在白名单内
   */
  private isInWhiteList(element: HTMLElement): boolean {
    return ToolKit.ui.element.isInSelectorList(element, this.currentConfig?.whiteList)
  }

  /**
   * 处理链接重定向
   * @param link 链接元素
   */
  private processLinkRedirect(link: HTMLAnchorElement) {
    // 查找匹配的规则
    const matchedRule = REDIRECT_RULES.find(rule =>
      new URL(link.href).hostname.includes(rule.domain),
    )

    if (matchedRule) {
      let targetUrl: string | null

      // 如果有参数名，从 URL 中提取目标
      if (matchedRule.paramName) {
        const urlObj = new URL(link.href)
        targetUrl = urlObj.searchParams.get(matchedRule.paramName)
      }
      else {
        // 如果没有参数名，直接使用链接的 href
        targetUrl = link.href
      }

      // 如果有自定义转换函数，应用转换
      if (targetUrl && matchedRule.transform) {
        targetUrl = matchedRule.transform(targetUrl)
      }

      // 如果成功获取目标 URL，进行跳转
      if (targetUrl) {
        // 确保 URL 有协议前缀
        if (!targetUrl.startsWith('http://') && !targetUrl.startsWith('https://')) {
          targetUrl = `http://${targetUrl}`
        }

        ToolKit.browser.url.openNewTab(targetUrl)
      }
      else {
        // 没有提取到目标 URL，按原链接处理
        ToolKit.browser.url.openNewTab(link.href)
      }
    }
    else {
      ToolKit.browser.url.openNewTab(link.href)
    }
  }

  applyConfig(config: Partial<Config>): void {
    super.updateConfig(config)
    this.setupLink()
    logger.info(`[${this.name}] Config updated and apply`, this.config)
  }
}
